package com.youme.tools.cg;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.List;

import com.youme.tools.cg.consts.ConstDef;
import com.youme.tools.cg.db.DbReader;
import com.youme.tools.cg.db.MySqlReader;
import com.youme.tools.cg.db.OracleReader;
import com.youme.tools.cg.db.SqlServerReader;
import com.youme.tools.cg.db.enums.DataSourceTypeEnum;
import com.youme.tools.cg.db.util.PropertiesReader;
import com.youme.tools.cg.pojo.TableBean;
import com.youme.tools.cg.util.NameFormatUtil;

public final class CodeGenerator {
  CodeGenerator() {}

  /** JDBC Driver Class Name */
  private static final String DRIVE_NAME =
      PropertiesReader.getInstance().getProperty("driver.name");

  /**
   * 文件生成入口
   * 
   * @param pkgName 基础包名，eg：com.xxx.spring.boot
   * @param createController 是否生成Controller文件
   * @param createService 是否生成Service层文件
   * @param createDAO 是否生成DAO层文件
   * @param createSqlmap 是否生成Sqlmap文件
   * @param tableNames 指定的表名集合，为空时，生成所有
   * @throws Exception 异常信息
   */
  public static void generate(String pkgName, boolean createController, boolean createService,
      boolean createDAO, boolean createSqlmap, List<String> tableNames) throws Exception {
    System.out.println("###### 生成文件开始 ######");
    // 文件保存的根目录
    String rootDir = ConstDef.DEFAULT_ROOT_DIR;
    System.out.println(String.format("##### 文件保存的根目录是：%s #####", rootDir));

    // 创建文件目录
    String controllerFilePath = "";
    String serviceFilePath = "";
    String serviceImplFilePath = "";
    String daoFilePath = "";
    String sqlmapFilePath = "";
    String modelFilePath = createDir(rootDir, pkgName + ConstDef.MODEL_PACKAGE_NAME);
    String dtoFilePath = createDir(rootDir, pkgName + ConstDef.DTO_PACKAGE_NAME);
    if (createController) {
      controllerFilePath = createDir(rootDir, pkgName + ConstDef.CONTROLLER_PACKAGE_NAME);
    }
    if (createService) {
      serviceFilePath = createDir(rootDir, pkgName + ConstDef.SERVICE_PACKAGE_NAME);
      serviceImplFilePath = createDir(rootDir, pkgName + ConstDef.SERVICE_IMPL_PACKAGE_NAME);
    }
    if (createDAO) {
      daoFilePath = createDir(rootDir, pkgName + ConstDef.DAO_PACKAGE_NAME);
    }
    if (createSqlmap) {
      sqlmapFilePath = createDir(rootDir, ConstDef.DEFAULT_PROPS_DIR);
    }

    // 读取数据库表文件信息
    DbReader dbReader = getDataStructureReader();
    List<TableBean> list = dbReader.readTable(tableNames);
    // 生成对应Java Model、DAO、Service、Controller
    if (null != list && !list.isEmpty()) {
      for (TableBean table : list) {
        createJavaModelFile(table, modelFilePath, pkgName + ConstDef.MODEL_PACKAGE_NAME);
        createDTOFile(table, dtoFilePath, pkgName + ConstDef.DTO_PACKAGE_NAME);
        if (createController) {
          createControllerFile(table, controllerFilePath, pkgName,
              pkgName + ConstDef.CONTROLLER_PACKAGE_NAME);
        }
        if (createService) {
          createServiceFile(table, serviceFilePath, pkgName,
              pkgName + ConstDef.SERVICE_PACKAGE_NAME);
          createServiceImplFile(table, serviceImplFilePath, pkgName,
              pkgName + ConstDef.SERVICE_IMPL_PACKAGE_NAME);
        }
        if (createDAO) {
          createDAOFile(table, daoFilePath, pkgName, pkgName + ConstDef.DAO_PACKAGE_NAME);
        }
        if (createSqlmap) {
          createSqlMap(table, sqlmapFilePath, pkgName + ConstDef.DAO_PACKAGE_NAME);
        }
      }
    }
    System.out.println("###### 生成文件结束 ######");
  }

  /**
   * 创建文档目录
   *
   * @param rootDir 根目录
   * @param pkgName 包名
   * @return 文档目录名称
   */
  private static String createDir(String rootDir, String pkgName) {
    StringBuilder path = new StringBuilder(rootDir);
    path.append(ConstDef.PACKAGE_SEPARATOR).append(pkgName);
    String filePath = path.toString().replace(ConstDef.PACKAGE_SEPARATOR, File.separator);
    File dir = new File(filePath);
    if (dir.exists()) {
      return filePath;
    }
    if (!filePath.endsWith(File.separator)) {
      filePath += File.separator;
    }
    dir.mkdirs();
    return filePath;
  }

  /**
   * 根据数据库类型选择数据库读取工具类
   * 
   * @Description: 根据数据库类型选择数据库读取工具类
   * @return 数据库读取工具类
   */
  private static DbReader getDataStructureReader() {
    DbReader reader = null;
    if (DRIVE_NAME.contains(DataSourceTypeEnum.MYSQL.getValue())) {
      reader = new MySqlReader();
    }
    if (DRIVE_NAME.contains(DataSourceTypeEnum.ORACLE.getValue())) {
      reader = new OracleReader();
    }
    if (DRIVE_NAME.contains(DataSourceTypeEnum.SQL_SERVER.getValue())) {
      reader = new SqlServerReader();
    }
    return reader;
  }

  public static DataSourceTypeEnum getDataBaseType() {
    DataSourceTypeEnum type = null;
    if (DRIVE_NAME.contains(DataSourceTypeEnum.MYSQL.getValue())) {
      type = DataSourceTypeEnum.MYSQL;
    }
    if (DRIVE_NAME.contains(DataSourceTypeEnum.ORACLE.getValue())) {
      type = DataSourceTypeEnum.ORACLE;
    }
    if (DRIVE_NAME.contains(DataSourceTypeEnum.SQL_SERVER.getValue())) {
      type = DataSourceTypeEnum.SQL_SERVER;
    }
    return type;
  }

  /**
   * 生成Java Entity文件
   *
   * @param table 表信息
   * @param filePath 文件目录
   * @param pkgName 包名
   * @throws Exception 异常信息
   */
  private static void createJavaModelFile(TableBean table, String filePath, String pkgName)
      throws Exception {
    String fileName = NameFormatUtil.formatClassName(table.getName());
    File file = new File(filePath + File.separator + fileName + ConstDef.JAVA_FILE_SUFFIX);
    String content = FileContentBuilder.createJavaModelFileContent(table, pkgName);
    createFile(file, content);
    System.out.println(String.format("===== 生成文件%s =====", file.getName()));
  }

  /**
   * 生成PageParam文件
   *
   * @param table 表信息
   * @param filePath 文件目录
   * @param pkgName 包名
   * @throws Exception 异常信息
   */
  private static void createDTOFile(TableBean table, String filePath, String pkgName)
      throws Exception {
    String fileName = NameFormatUtil.formatClassName(table.getName());
    File file =
        new File(filePath + File.separator + fileName + "PageParam" + ConstDef.JAVA_FILE_SUFFIX);
    String content = FileContentBuilder.createDTOFileContent(table, pkgName);
    createFile(file, content);
    System.out.println(String.format("===== 生成文件%s =====", file.getName()));
  }

  /**
   * 生成SqlMap文件
   * 
   * @param table 表信息
   * @param filePath 文件目录
   * @param pkgName 包名
   * @throws Exception 异常信息
   */
  private static void createSqlMap(TableBean table, String filePath, String pkgName)
      throws Exception {
    String fileName = NameFormatUtil.formatFieldName(table.getName());
    fileName = String.format(ConstDef.SQLMAP_FILE_NAME, fileName);
    File file = new File(filePath + File.separator + fileName);
    String content = FileContentBuilder.createSqlMapContent(table, pkgName);
    createFile(file, content);
    System.out.println(String.format("===== 生成文件%s =====", file.getName()));
  }

  /**
   * 生成 DAO接口文件
   *
   * @param table 表信息
   * @param filePath 文件目录
   * @param pkgName 包名
   * @throws Exception 异常信息
   */
  private static void createDAOFile(TableBean table, String filePath, String pkgName,
      String moduleName) throws Exception {
    String fileName =
        NameFormatUtil.formatClassName(table.getName()) + "DAO" + ConstDef.JAVA_FILE_SUFFIX;
    File file = new File(filePath + File.separator + fileName);
    String content = FileContentBuilder.createDAOFileContent(table, pkgName, moduleName);
    createFile(file, content);
    System.out.println(String.format("===== 生成文件%s =====", file.getName()));
  }

  /**
   * 生成Service接口文件
   * 
   * @param table 表信息
   * @param filePath 文件目录
   * @param pkgName 包名
   * @throws Exception 异常信息
   */
  private static void createServiceFile(TableBean table, String filePath, String pkgName,
      String moduleName) throws Exception {
    String fileName =
        NameFormatUtil.formatClassName(table.getName()) + "Service" + ConstDef.JAVA_FILE_SUFFIX;
    File file = new File(filePath + File.separator + fileName);
    String content = FileContentBuilder.createServiceFileContent(table, pkgName, moduleName);
    createFile(file, content);
    System.out.println(String.format("===== 生成文件%s =====", file.getName()));
  }

  /**
   * 生成Service实现类文件
   * 
   * @param table 表信息
   * @param filePath 文件目录
   * @param pkgName 包名
   * @throws Exception 异常信息
   */

  private static void createServiceImplFile(TableBean table, String filePath, String pkgName,
      String moduleName) throws Exception {
    String fileName =
        NameFormatUtil.formatClassName(table.getName()) + "ServiceImpl" + ConstDef.JAVA_FILE_SUFFIX;
    File file = new File(filePath + File.separator + fileName);
    String content = FileContentBuilder.createServiceImplFileContent(table, pkgName, moduleName);
    createFile(file, content);
    System.out.println(String.format("===== 生成文件%s =====", file.getName()));
  }

  /**
   * 生成Controller文件
   * 
   * @param table 表信息
   * @param filePath 文件目录
   * @param pkgName 包名
   * @throws Exception 异常信息
   */
  private static void createControllerFile(TableBean table, String filePath, String pkgName,
      String moduleName) throws Exception {
    String fileName = NameFormatUtil.formatClassName(table.getName()) + "RestController"
        + ConstDef.JAVA_FILE_SUFFIX;
    File file = new File(filePath + File.separator + fileName);
    String content = FileContentBuilder.createControllerFileContent(table, pkgName, moduleName);
    createFile(file, content);
    System.out.println(String.format("===== 生成文件%s =====", file.getName()));
  }

  /**
   * 写文件
   * 
   * @param file 文件
   * @param content 文件内容
   * @throws FileNotFoundException
   * @throws IOException
   */
  private static void createFile(File file, String content)
      throws FileNotFoundException, IOException {
    byte bytes[] = new byte[1024];
    bytes = content.getBytes();
    FileOutputStream in = new FileOutputStream(file);
    in.write(bytes, 0, bytes.length);
    in.close();
  }

}
